package manager;

import java.util.*;

import org.hibernate.Session;

import util.HibernateSessionFactory;
import static util.MD5.*;

import model.*;
import dao.*;

/**
 * Managing User, using singleton
 * 
 * @author xbingo
 * 
 */
public class UserManager {
	private static UserDAO userDao = new UserDAO();
	private static ProfileDAO profileDao = new ProfileDAO();
	private static SettingDAO settingDao = new SettingDAO();
	private static UserManager userManager = new UserManager();

	private UserManager() {

	}

	/**
	 * 
	 * @return UserManager instance
	 */
	public static UserManager getUserManager() {

		return userManager;
	}

	public UserDAO getUserDAO() {
		return userDao;
	}

	public ProfileDAO getProfileDAO() {
		return profileDao;
	}

	public SettingDAO getSettingDAO() {
		return settingDao;
	}

	/**
	 * 
	 * @return default setting
	 */
	private Setting getDefaultSetting() {
		// initialize default setting
		Setting defaultSetting = new Setting();
		defaultSetting.setCompiler(CompilerManager.getCompilerManager()
				.getDefaultCompiler());
		defaultSetting.setTheme("default");
		return defaultSetting;
	}

	/**
	 * 
	 * @param user
	 *            The user to be registered.
	 * @throws UserAlreadyExistsException
	 * @return the user registered if successful.
	 */
	public User register(User user) throws UserAlreadyExistsException {
		List<User> list = getUserDAO().findByUsername(user.getUsername());
		if (!list.isEmpty()) {
			throw new UserAlreadyExistsException();
		} else {
			Session session = HibernateSessionFactory.getSession();
			session.beginTransaction();

			Profile profile = new Profile();
			profile.setUser(user);
			Setting setting = getDefaultSetting();

			user.setRegisterDate(new Date());
			user.setLastLoginDate(new Date());
			user.setProfile(profile);
			user.setSetting(setting);
			user.setType("user");

			Category category = CategoryManager.getCategoryManager()
					.getDefaultCategory();
			category.setUser(user);
			user.getCategories().add(category);

			getUserDAO().save(user);
			getSettingDAO().save(setting);
			CategoryManager.getCategoryManager().save(category);
			getProfileDAO().save(profile);

			session.getTransaction().commit();
		}
		return user;
	}

	/**
	 * Validate the user name and password,<br>
	 * then returns the user object when the validation is OK. <br>
	 * <b>Notice that for safety, you should give the md5 code of the password
	 * instead of itself.</b>
	 * 
	 * @return the user object
	 * @throws UserNotExist
	 * @throws PasswordIncorrect
	 */
	public User login(String username, String md5Password) throws UserNotExist,
			PasswordIncorrect {
		User user;
		List<User> list = getUserDAO().findByUsername(username);
		if (list.size() == 0)
			throw new UserNotExist();
		user = list.get(0);

		if (getMD5(user.getPassword()).equals(md5Password))
			return user;
		else
			throw new PasswordIncorrect();
	}

	/**
	 * Update the profile of user.
	 * 
	 * @param user
	 */
	public void updateProfile(User user) {
		getProfileDAO().save(user.getProfile());
	}

	/**
	 * 
	 * Update the setting of user.
	 * 
	 * @param user
	 * 
	 */
	public void updateSettiong(User user) {
		getSettingDAO().save(user.getSetting());
	}

	/**
	 * Find user by username
	 * @param username
	 * @return return null if user not found
	 */
	public User find(String username){
		ArrayList<User> list =(ArrayList<User>) userDao.findByUsername(username);
		if(list == null || list.isEmpty())
			return null;
		return list.get(0);
	}
}
